#include <iostream>
#include <iomanip>
#include "Epix3D.h"
#include "Perlin.h"
#include "code.h"

#define TAILLE 1024

// smooth terrain
#define OCTAVES 7
#define PAS 128
#define PERSISTANCE 0.5
#define DEEP 0.5

using namespace std;
using namespace epix;

typedef TMesh<DVBO> Mesh;
typedef TImage<DVBO> Image;
typedef TImage3D<DVBO> Image3D;
typedef THeightmap<DVBO> Heightmap;

float LX = 0;
float LY = 0;
float LZ = 120;

int main(int argc, char **argv)
{
	int width = 1024, height = 1024;
	bool fullscreen = false;

	if(argc >= 3)
    {
      istringstream iss1(argv[1]);
      iss1 >> width;
      istringstream iss2(argv[2]);
      iss2 >> height;
      if(argc >= 4)
		fullscreen = true;
    }
	
	Window *window = Window::instance();
	Renderer *rdr = window->getRenderer();
	EventManager *emgr = window->getEventManager();

	window->init(width, height, fullscreen);
	window->showCursor(false);
	
	rdr->initExtensions();

	FreeFlyCamera cam(Vector3d(0, 0, 150));
	cam.setSensivity(0.2);
	cam.setSpeed(50.0);

	Shader light("shaders/light.vert", "shaders/light.frag");

	Skybox skybox("textures/back.jpg", "textures/front.jpg",
								"textures/bottom.jpg", "textures/top.jpg",
								"textures/right.jpg", "textures/left.jpg");
	skybox.setSize(100.0f);

	////////// GEN HEIGHTMAP TEXTURE ///////////////
	float *data = new float[TAILLE*TAILLE];
	unsigned char *tex_data = new unsigned char[TAILLE*TAILLE*4];
	initPerlin2D(TAILLE+1, TAILLE+1, PAS, OCTAVES);
	int pc = 0;
	for(int i=0; i<TAILLE; i++)
	{
		for(int j=0; j<TAILLE*4; j+=4)
		{
			data[i*TAILLE+j/4] = bruit_de_perlin2D(i, j/4, PERSISTANCE) * 255;
			seuil(tex_data, i*TAILLE*4+j, data[i*TAILLE+j/4]);
		}
		int ptmp = ((float)i/TAILLE)*100;
		if(ptmp > pc+2)
		{
			pc = ptmp;
			cout << pc << "%" << endl;
		}
	}	
	destroyPerlin2D();
	Image img(new Texture(Vector2i(TAILLE, TAILLE), tex_data, "perlin"));
	img.setSize(256, 256);
	
	Heightmap heightmap(data, TAILLE, TAILLE, DEEP);
	heightmap.genNormals();
	heightmap.genTexCoords();
	heightmap.setTexture(img.getTexture());

	delete[] data;
	////////////////////////////////////////////////
	
	bool shading = false, drawNormals = false;
	while(window->run())
    {
		window->setWindowTitle("Heightmap !", true);
		emgr->getEvent();
		cam.onEvent();
		cam.animate();
		skybox.setPosition(cam.getPosition());

		rdr->beginScene();
		cam.look();
		
		skybox.draw();
		heightmap.draw();
		light.setShader(false);
		lightning(LX, LY, LZ);
		if(drawNormals)
			heightmap.drawNormals();
		
		rdr->set2DMode();
		img.draw();
		rdr->end2DMode();
		light.setShader(shading);

		rdr->endScene();

		if(emgr->quit()) window->closeWindow();
		else if(emgr->isKeyDownOnce(GLFW_KEY_ESC)) window->closeWindow();
		else if(emgr->isKeyDownOnce('A')) window->showCursor(false);
		else if(emgr->isKeyDownOnce('E')) window->showCursor(true);
		else if(emgr->isKeyDownOnce('I'))
		{
			light.setShader(false);
			shading = false;
		}
		else if(emgr->isKeyDownOnce('O'))
		{
			light.setShader(true);
			shading = true;
		}
		else if(emgr->isKeyDownOnce('K'))
			rdr->setPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
		else if(emgr->isKeyDownOnce('L'))
			rdr->setPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
		else if(emgr->isKeyDownOnce('M'))
			rdr->setPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
		else if(emgr->isKeyDownOnce('N')) drawNormals = !drawNormals;
		if(emgr->isKeyDown('Y')) LY++;
		if(emgr->isKeyDown('G')) LX--;
		if(emgr->isKeyDown('H')) LY--;
		if(emgr->isKeyDown('J')) LX++;
		if(emgr->isKeyDown('W')) LZ--;
		if(emgr->isKeyDown('X')) LZ++;
    }
	
	img.save("perlin.bmp");
	
	heightmap.clear();
	img.clear();
	light.clear();

	Window::destroy();

	return 0;
}
